import threading
import time
from django.utils import timezone
import random
from events.service.purchase_simulator_service import PurchaseSim
import chinese_calendar as China
from datetime import datetime, timedelta
from django.utils.timezone import make_aware
from collections import defaultdict
from events.service.storage_simulator_service import StorageSimulatorService


class PurchaseThread:
    def __init__(self, max_threads=8, start_datetime=None, end_datetime=None):
        self.current_time = None
        self.simulation_thread = None
        self.max_threads = max_threads
        self.is_running = False
        self.threads = []
        self.calendar = China
        self.current_datetime = start_datetime
        self.end_datetime = end_datetime
        self.daily_orders = defaultdict(list)
        self.is_historical_mode = start_datetime is not None and end_datetime is not None

    def get_delay_probability(self):
        """获取不同时段的下单概率"""
        now = self.current_time
        current_hour = now.hour
        weekday = now.weekday()
        is_holiday = self.calendar.is_holiday(now.date())
        
        # 基础概率
        base_prob = 1.0
        
        # 节假日
        if is_holiday:
            if 10 <= current_hour < 12:
                return base_prob * 1.25
            elif 12 <= current_hour < 20:
                return base_prob * 3.33
            else:
                return base_prob * 2
        # 工作日
        elif weekday < 5:
            if 10 <= current_hour < 12:
                return base_prob * 0.33
            elif 12 <= current_hour < 14:
                return base_prob
            elif 14 <= current_hour < 17:
                return base_prob * 0.5
            elif 17 <= current_hour < 20:
                return base_prob * 1.25
            else:
                return base_prob * 0.67
        # 周末
        else:
            if 10 <= current_hour < 12:
                return base_prob * 0.67
            elif 12 <= current_hour < 20:
                return base_prob * 2
            else:
                return base_prob

    def generate_daily_orders(self):
        """生成一天的订单时间"""
        self.daily_orders.clear()
        
        # 获取当天的日期
        current_date = self.current_datetime.date()
        
        # 如果是第一天，使用传入的开始时间
        if current_date == self.current_datetime.date():
            start_time = self.current_datetime
        else:
            # 其他天从早上10点开始
            start_time = make_aware(datetime.combine(current_date, datetime.min.time().replace(hour=10)))
            
        # 如果是最后一天，使用传入的结束时间
        if current_date == self.end_datetime.date():
            end_time = self.end_datetime
        else:
            # 其他天到晚上10点结束
            end_time = make_aware(datetime.combine(current_date, datetime.min.time().replace(hour=22)))
            
        # 确保时间在营业时间内（10:00-22:00）
        start_time = max(
            start_time,
            make_aware(datetime.combine(current_date, datetime.min.time().replace(hour=10)))
        )
        end_time = min(
            end_time,
            make_aware(datetime.combine(current_date, datetime.min.time().replace(hour=22)))
        )
        
        # 直接生成整天的订单
        current_time = start_time
        orders = []
        
        while current_time < end_time:
            # 获取当前时段的延迟时间
            self.current_time = current_time
            delay = self.get_delay_time()
            
            # 基于延迟时间计算下一个订单时间间隔
            next_delay = random.uniform(delay * 0.8, delay * 1.2)  # 添加±20%的随机波动
            
            # 生成下一个订单时间
            next_time = current_time + timedelta(seconds=next_delay)
            
            # 如果超出结束时间，退出循环
            if next_time > end_time:
                break
            
            # 添加订单时间
            orders.append(next_time)
            
            # 更新当前时间
            current_time = next_time
        
        # 将所有订单存储在默认时间槽中（使用0作为键）
        self.daily_orders = orders

    def simulate_purchase_at_time(self, target_time):
        """在指定时间模拟购买"""
        # 修改当前时间
        timezone.now = lambda: target_time

        simulator = PurchaseSim()
        purchase_df = simulator.purchase()

        if simulator.consumer.blanket:
            simulator.insert_purchase_data(purchase_df)

    def should_generate_delivery(self, current_date):
        """判断是否应该生成补货建议（周一、周三、周五）"""
        weekday = current_date.weekday()
        return weekday in [0, 2, 4]  # 0=周一, 2=周三, 4=周五

    def run_historical_simulation(self):
        """运行历史数据模拟（补数据模式）"""
        while self.is_running and self.current_datetime <= self.end_datetime:
            # 生成当天的订单
            self.generate_daily_orders()

            # 按时间顺序处理所有订单
            all_orders = self.daily_orders
            # all_orders = []
            # for hour_orders in self.daily_orders.values():
            #     all_orders.extend(hour_orders)
            # all_orders.sort()
            
            # 执行所有订单
            for order_time in all_orders:
                if not self.is_running:
                    break
                self.simulate_purchase_at_time(order_time)
            
            # 每天都执行7天前补货建议的库存更新
            storage_service = StorageSimulatorService()
            storage_service.process_seven_days_ago_replenishment(self.current_datetime.date())
            
            # 执行每日库存快照
            from product.service.product_snapshot import ProductInventorySnapshotService
            snapshot_service = ProductInventorySnapshotService()
            snapshot_service.create_daily_snapshot(self.current_datetime.date())
            
            # 仅在周一、周三、周五生成补货建议
            if self.should_generate_delivery(self.current_datetime.date()):
                from delivery.service.delivery_generate import generate_and_save_delivery
                generate_and_save_delivery()
                storage_service.update_today_replenishment(self.current_datetime.date())
            
            # 进入下一天
            next_day = self.current_datetime.date() + timedelta(days=1)
            self.current_datetime = make_aware(datetime.combine(next_day, datetime.min.time().replace(hour=10)))
            
        self.is_running = False

    def run_realtime_simulation(self):
        """运行实时模拟"""
        while self.is_running:
            if not self.is_business_hours():
                time.sleep(60)  # 非营业时间每分钟检查一次
                continue
                
            # 当前活跃线程数
            active_threads = len([t for t in self.threads if t.is_alive()])
            
            # 如果活跃线程少于最大线程数，创建新的购买线程
            if active_threads < self.max_threads:
                # 创建新的购买线程
                thread = threading.Thread(target=self.simulate_purchase)
                thread.start()
                self.threads.append(thread)
                
                # 根据时间获取延迟
                delay = self.get_delay_time()
                # 添加随机波动（±20%）
                delay *= random.uniform(0.8, 1.2)
                time.sleep(delay)
            
            # 清理已完成的线程
            self.threads = [t for t in self.threads if t.is_alive()]

    def run_simulation(self):
        """运行模拟线程"""
        if self.is_historical_mode:
            self.run_historical_simulation()
        else:
            self.run_realtime_simulation()

    def start(self):
        """启动模拟器"""
        if not self.is_running:
            self.is_running = True
            self.simulation_thread = threading.Thread(target=self.run_simulation)
            self.simulation_thread.start()
    
    def stop(self):
        """停止模拟器"""
        self.is_running = False
        if hasattr(self, 'simulation_thread'):
            self.simulation_thread.join()

    def is_business_hours(self):
        """判断当前是否在营业时间内（10:00-22:00）"""
        now = timezone.localtime()
        current_hour = now.hour
        return 10 <= current_hour < 22

    def simulate_purchase(self):
        """执行单次购买模拟"""
        simulator = PurchaseSim()
        purchase_df = simulator.purchase()
        
        if simulator.consumer.blanket:
            simulator.insert_purchase_data(purchase_df)

    def get_delay_time(self):
        """获取延迟时间，基于当前时间、日期和节假日"""
        now = timezone.localtime()
        current_hour = now.hour
        weekday = now.weekday()  # 0-6，0是周一
        is_holiday = self.calendar.is_holiday(now.date())
        
        # 基础延迟时间（秒），随机20-55秒
        base_delay = random.uniform(20, 55)
        
        # 节假日
        if is_holiday:
            # 早上时段 (10:00-12:00)
            if 10 <= current_hour < 12:
                return base_delay * 0.8
            # 中午到晚上高峰时段 (12:00-20:00)
            elif 12 <= current_hour < 20:
                return base_delay * 0.3
            # 收尾时段 (20:00-22:00)
            else:
                return base_delay * 0.5
        # 工作日
        elif weekday < 5:
            if 10 <= current_hour < 12:
                return base_delay * 3
            elif 12 <= current_hour < 14:
                return base_delay
            elif 14 <= current_hour < 17:
                return base_delay * 2
            elif 17 <= current_hour < 20:
                return base_delay * 0.8
            else:
                return base_delay * 1.5
        # 周末
        else:
            if 10 <= current_hour < 12:
                return base_delay * 1.5
            elif 12 <= current_hour < 20:
                return base_delay * 0.5
            else:
                return base_delay

